//#include "prefetch.h"
//#include "llvm/Transforms/Utils/Cloning.h"
//#include "llvm/LLVMContext.h"
//#include "llvm/Module.h"
//#include "llvm/Type.h"
//#include "llvm/ADT/Triple.h"
//#include "llvm/Bitcode/ReaderWriter.h"
//#include "llvm/CodeGen/LinkAllCodegenComponents.h"
//#include "llvm/ExecutionEngine/GenericValue.h"
//#include "llvm/ExecutionEngine/Interpreter.h"
//#include "llvm/ExecutionEngine/JIT.h"
//#include "llvm/ExecutionEngine/JITEventListener.h"
//#include "llvm/Support/Casting.h"
//#include "llvm/Support/IRReader.h"
//#include "llvm/Support/ManagedStatic.h"
//#include "llvm/Support/MemoryBuffer.h"
//#include "llvm/Support/PluginLoader.h"
//#include "llvm/Support/PrettyStackTrace.h"
//#include "llvm/Support/raw_ostream.h"
//#include "llvm/Support/FormattedStream.h"
//#include "llvm/Target/TargetSelect.h"
//#include "llvm/Instructions.h"
//#include "llvm/PassManager.h"
//#include "llvm/Target/TargetRegistry.h"
//#include "llvm/Pass.h"
//#include <cerrno>
//#include <stdlib.h>
//#include <unistd.h>
//#include <stdio.h>
//#include <signal.h>
//#include <time.h>
//#include <execinfo.h>
//#include <vector>
//#include <pthread.h>
//#include <map>
//#include <set>
//#include <queue>
//#include <sstream>
//#include <iostream>
//#include <inttypes.h>
//#include "llvm/Support/Signals.h"
//#include "llvm/Support/Process.h"
//#include "llvm/Transforms/Utils/Cloning.h"
//#include "llvm/Transforms/IPO.h"
//#include "llvm/Support/IRBuilder.h"
//#include "llvm/Analysis/Verifier.h"
//
//using namespace llvm;
//
//typedef std::set<Instruction*> iset;
//
//static Module *M;
//static ExecutionEngine *EE;
//
//void prefetch_init(Module *_M, ExecutionEngine *_EE) {
//	M = _M;
//	EE = _EE;
//}
//
//static void InsertLog(Instruction *Before, int Val) {
//  Function *LogF = M->getFunction("_log");
//  LLVMContext &C = Before->getContext();
//  std::vector<Value*> Args;
//  Args.push_back(ConstantInt::get(Type::getInt32Ty(C), Val));
//  CallInst::Create(LogF, Args.begin(), Args.end(), "", Before);
//}
//
//static Function* Slice(Instruction *Inst, bool byPrediction) {
//  Function *F = Inst->getParent()->getParent();
//	Twine SliceName("__", F->getName());
//	Function *NF = M->getFunction(SliceName.str());
//
//	//NF->getBasicBlockList().clear();
//	NF->dropAllReferences();
//
//	ValueToValueMapTy VMap;
//	SmallVector<ReturnInst*, 8> Returns;
//
//	Function::arg_iterator DestI = NF->arg_begin();
//  for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) {
//		DestI->setName(I->getName());
//		VMap[I] = DestI++;
//	}
//
//
//	CloneFunctionInto(NF, F, VMap, true, Returns);
//
//	// compatablity; TODO: refactor
//	Function *OldF = F;
//  F = NF;
//
//  Instruction *NInst = dyn_cast<Instruction>(VMap[Inst]);
//
//  std::queue<User*> pending; // working queue (to avoid recursion)
//  std::set<Value*> vital; // instructions in slice
//
//  pending.push(NInst); // insert the hot load
//  vital.insert(NInst);
//  for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { // insert all terminators
//    pending.push(FI->getTerminator());
//    vital.insert(FI->getTerminator());
//  }
//
//	//insert all stores
//	/*
//	for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI)
//		for (BasicBlock::iterator BBI = FI->begin(), BBE = FI->end(); BBI != BBE; ++BBI)
//			if (StoreInst *SI = dyn_cast<StoreInst>(&*BBI)) {
//				pending.push(SI);
//				vital.insert(SI);
//			}
//	*/
//
//	for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
//		for (BasicBlock::iterator BBI = FI->begin(), BBE = FI->end(); BBI != BBE; ++BBI) {
//			if (CallInst *inst = dyn_cast<CallInst>(&*BBI)) {
//				if (Function *CalledFunc = inst->getCalledFunction()) {
//					if (CalledFunc->getNameStr() == "printf" || CalledFunc->getNameStr() == "exit") {
//						pending.push(inst);
//						vital.insert(inst);
//					}
//					if (CalledFunc == OldF)
//						inst->setCalledFunction(NF);
//				}
//			}
//		}
//	}
//
//  while (!pending.empty()) { // handle all pending instructions
//    User *I = pending.front();
//    pending.pop();
//    for (User::op_iterator OI = I->op_begin(), OE = I->op_end(); OI != OE; ++OI) {
//			if (vital.find(*OI) == vital.end()) {
//				vital.insert(*OI);
//				if (User *NI = dyn_cast<User>(*OI))
//          pending.push(NI);
//			}
//    }
//  }
//
//  // retain only vital instructions
//  std::set<Instruction*> complementary;
//  for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI)
//    for (BasicBlock::iterator BBI = FI->begin(), BBE = FI->end(); BBI != BBE; ++BBI) {
//      Instruction *I = &*BBI;
//      if (vital.find(I) == vital.end())
//        complementary.insert(&*BBI);
//    }
//  for (std::set<Instruction*>::iterator i = complementary.begin(), e = complementary.end(); i != e; ++i) {
//		(*i)->replaceAllUsesWith(UndefValue::get((*i)->getType()));
//    (*i)->eraseFromParent();
//	}
//
//	LLVMContext &C = NInst->getContext();
//
////  Function *prefetch = M->getFunction("_prefetch");
////  Value *addr = new BitCastInst(NInst->getOperand(0), Type::getInt8PtrTy(C), "bitcast", NInst);
////  Value *id = ConstantInt::get(Type::getInt32Ty(C), inst2counter[Inst]);
////  Value *args[] = {addr, id};
////  CallInst::Create(prefetch, args, args + 2, "", NInst);
//  //NInst->eraseFromParent();
//
//  // instrument dependant branches
//
//  Function *branch_taken = M->getFunction("_branch_taken");
//  Function *branch_predict = M->getFunction("_branch_predict");
//
////  if (!byPrediction) {
////    for (Value::use_iterator UI = NInst->use_begin(), UE = NInst->use_end(); UI != UE; ++UI)
////      if (CmpInst *CmpI = dyn_cast<CmpInst>(*UI)) {
////        branch2counter[CmpI] = branch_counter;
////        Value *id = ConstantInt::get(Type::getInt32Ty(C), branch_counter);
////        Value *args[] = {id, CmpI};
////        CallInst *CI = CallInst::Create(branch_taken, args, args + 2);
////        CI->insertAfter(CmpI);
////        ++branch_counter;
////      } else {
////        errs() << "hot load used by " << **UI << "\n";
////        exit(0);
////      }
////  } else {
////    std::vector<Instruction*> ToBeErased;
////    for (Value::use_iterator UI = NInst->use_begin(), UE = NInst->use_end(); UI != UE; ++UI)
////      if (CmpInst *CmpI = dyn_cast<CmpInst>(*UI)) { // always true
////        Value *id = ConstantInt::get(Type::getInt32Ty(C), branch2counter[CmpI]);
////        Value *args[] = {id};
////        CallInst *CI = CallInst::Create(branch_predict, args, args + 1);
////        CI->insertAfter(CmpI);
////        CmpI->replaceAllUsesWith(CI);
////        ToBeErased.push_back(CmpI);
////      } else {
////				errs() << "hot load used by " << **UI << "\n";
////        exit(0);
////			}
////    for (std::vector<Instruction*>::iterator VI = ToBeErased.begin(), VE = ToBeErased.end(); VI != VE; ++VI) {
////			(*VI)->eraseFromParent();
////    }
////    NInst->eraseFromParent();
////
////		std::map<int, Instruction*> one;
////		std::map<Instruction*, int> two;
//
////		InsertCounters(F, M->getFunction("_check_new"), one, two);
//
////		F->dump();
////  }
//
//
//	llvm::verifyFunction(*F, llvm::AbortProcessAction);
//  return F;
//}
//
//std::map<Function*,int> function2int;
//std::map<int, Function*> slices;
//std::map<int, Function*> origs;
//
//std::vector<Instruction*> Optimize1These;
//std::vector<Instruction*> Optimize2These;
//
//#define LIB(X,Y) X *Y = (X*)EE->getPointerToGlobal(Mod->getGlobalVariable(#Y))
//
//std::map<Function*, GlobalVariable*> ShouldForks;
//
//void RecompileSlices() {
//	errs() << "Creating slices.. \n";
//
//	for (std::vector<Instruction*>::iterator I = Optimize2These.begin(), E = Optimize2These.end(); I != E; ++I) {
//		Instruction *Inst = *I;
//		Function *F = Inst->getParent()->getParent();
//		errs() << "Optimizing2 " << *Inst << " from " << F->getName() << " [" << function2int[F] << "]\n";
//
//		EE->recompileAndRelinkFunction(Slice(Inst, true));
//
//		*((int32_t*)EE->getPointerToGlobal(ShouldForks[F])) = 1;
//
//	}
//	Optimize2These.clear();
//
//
//	for (std::vector<Instruction*>::iterator I = Optimize1These.begin(), E = Optimize1These.end(); I != E; ++I) {
//		Instruction *Inst = *I;
//		Function *F = Inst->getParent()->getParent();
//		errs() << "Optimizing1 " << *Inst << " from " << F->getName() << " [" << function2int[F] << "]\n";
//
//		EE->recompileAndRelinkFunction(Slice(Inst, false));
//
//		*((int32_t*)EE->getPointerToGlobal(ShouldForks[F])) = 1;
//		Optimize2These.push_back(Inst);
//	}
//	Optimize1These.clear();
//}
//
//void* monitor(void *data) {
///*
//	LLVMContext &C = M->getContext();
//
//	FunctionType *FuncTy = FunctionType::get(Type::getVoidTy(C), false);
//	M->getOrInsertFunction("RecompileSlices", FuncTy);
//
//	EE->addGlobalMapping(M->getNamedGlobal("RecompileSlices"), (void*)&RecompileSlices);
//
//  int64_t *cs = (int64_t*)EE->getPointerToGlobal(M->getGlobalVariable("counters"));
//  int64_t *totals = (int64_t*)EE->getPointerToGlobal(M->getGlobalVariable("totals"));
//  int8_t *dump_fetches = (int8_t*)EE->getPointerToGlobal(M->getGlobalVariable("dump_fetches"));
//  bool *should_profile = (bool*)EE->getPointerToGlobal(M->getGlobalVariable("should_profile"));
//
//  typedef void* (*thread_func)(void*);
//  thread_func *prefetch_funcs = (thread_func*)EE->getPointerToGlobal(M->getGlobalVariable("prefetch_funcs"));
//  thread_func *predicted_prefetch_funcs = (thread_func*)EE->getPointerToGlobal(M->getGlobalVariable("predicted_prefetch_funcs"));
//
//  for (;;) {
//		struct timespec large_delay = { 20, 0}, small_delay = {1, 0};
//		nanosleep(&large_delay, 0);
//		*should_profile = true;
//		nanosleep(&small_delay, 0);
//    *should_profile = false;
//		nanosleep(&small_delay, 0);
//    errs() << "STATS\n";
//    int max = 0;
//		int csmax = 0;
//    for (int i = 0; i < 1000; ++i) {
//			if (cs[i] > 0)
//				errs() << "  " << i << "\t" << (cs[i] * 100 / totals[i]) << "\n";
//			if (cs[i] > csmax && counter2inst[i])
//				csmax = cs[max = i];
//			cs[i] = 0;
//			totals[i] = 0;
//		}
//    if (csmax > 0) {
//      Instruction *I = counter2inst[max];
//      Function *F = I->getParent()->getParent();
//      int n = function2int[F];
//      errs() << "hottest load (" << csmax << "): " << *I << " in " << F->getName() << "[" << n << "]\n";
//			Optimize1These.push_back(I);
//			prefetch_funcs[n] = (void* (*)(void*))1;
//			dump_fetches[max] = 1;
//
//			break;
//			//optimize(I, false);
//
//			origs[n] = F;
//			slices[n] = Slice(I, false); // byPrediction = false
//
//
////      prefetch_funcs[n] = (thread_func)optimize(I, false);
////      predicted_prefetch_funcs[n] = (thread_func)optimize(I, true);
//
//      errs() << "stopping monitoring\n";
//      break;
//    }
//    for (int i = 0; i < 1000; ++i)
//      cs[i] = 0;
//  }
//*/
//  return 0;
//}
//
//void InstrumentFunction(Function *F) {
////  LLVMContext &C = M->getContext();
////	IRBuilder<> Builder(C);
////
////	if (function2int.find(F) == function2int.end())
////		function2int[F] = function2int.size();
////
////	Builder.SetInsertPoint(F->front().getFirstNonPHI());
////	Builder.CreateCall(M->getFunction("_entered_func"),
////										 ConstantInt::get(Type::getInt32Ty(C), function2int[F]));
////
////	std::vector<Value*> Args;
////	for (Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
////		Args.push_back(&*AI);
////	Builder.CreateCall(GenerateStub(F), Args.begin(), Args.end());
////
////
////	Builder.SetInsertPoint(F->back().getTerminator());
////
////
////	Builder.CreateCall2(M->getFunction("_exited_func"),
////										  ConstantInt::get(Type::getInt32Ty(C), function2int[F]),
////											Builder.CreateLoad(PIDs[F]));
////
////	llvm::verifyFunction(*F, llvm::AbortProcessAction);
//}

